package cn.sciento.farm.devicemanager.gateway.uplink.service.sensor;

import cn.sciento.farm.devicemanager.common.constant.CollectionTypeEnum;
import cn.sciento.farm.devicemanager.common.constant.DeviceConstant;
import cn.sciento.farm.devicemanager.common.constant.MqttConstant;
import cn.sciento.farm.devicemanager.common.constant.RedisConstant;
import cn.sciento.farm.devicemanager.common.util.LogManager;
import cn.sciento.farm.devicemanager.common.util.RedisUtil;
import cn.sciento.farm.devicemanager.dao.entity.DevCollection;
import cn.sciento.farm.devicemanager.dao.entity.DevCollectionHistory;
import cn.sciento.farm.devicemanager.dao.entity.DevController;
import cn.sciento.farm.devicemanager.dao.entity.DevDevice;
import cn.sciento.farm.devicemanager.gateway.downlink.service.impl.MqttSendService;
import cn.sciento.farm.devicemanager.gateway.model.downlink.MqttContent;
import cn.sciento.farm.devicemanager.gateway.model.uplink.*;
import cn.sciento.farm.devicemanager.gateway.uplink.service.base.LogTaskFactory;
import cn.sciento.farm.devicemanager.service.CollectionHistoryService;
import cn.sciento.farm.devicemanager.service.CollectionService;
import cn.sciento.farm.devicemanager.service.ControllerService;
import cn.sciento.farm.devicemanager.service.DeviceService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * @author wumu
 * @version V1.0
 * @date 2/27/18
 * @time 4:25 PM
 */
@Slf4j
@Order(1)
@Service(value = "DatabaseDisposeService")
public class DatabaseDisposeService extends AbstractMessageDisposeService {



    @Autowired
    private CollectionHistoryService collectionHistoryService;

    @Autowired
    private CollectionService collectionService;

    @Autowired
    private ControllerService controllerService;


    @Autowired
    private DeviceService deviceService;

    @Autowired
    private AlarmDisposeService alarmService;

    @Autowired
    private MqttSendService mqttSendService;



    /**
     * 网关上下线
     *
     */
    @Override
    public void changeOnline(DeviceStatus deviceStatus) {
        int up = deviceStatus.getStatus();
        String eui = deviceStatus.getEui();
        String node = deviceStatus.getNode();
        String circuit = deviceStatus.getCircuit();
        DevDevice device = deviceService.getById(eui);
        if (device == null) {
            return;
        }
        if (up == MqttConstant.NODE_JOIN_CODE) {
            // 入网,lorawan入网
            deviceService.updateStatus(eui, MqttConstant.NODE_JOIN_CODE);
        } else {
            if(StringUtils.isEmpty(node)){
                deviceService.updateOnline(eui, up);
                controllerService.updateOnline(eui, node,circuit ,up);
                collectionService.updateOnline(eui, node,circuit, up);
            }else {
                if(up == MqttConstant.DEVICE_OFFLINE_CODE){
                    deviceService.updateOnline(eui, up);
                }
                controllerService.updateOnline(eui, node,circuit ,up);
                collectionService.updateOnline(eui, node,circuit, up);
            }

            LogManager.getInstance().executeLog(LogTaskFactory.logOnline(device, node, System.currentTimeMillis(), up));
        }
//        sendUserStatus(eui, node,extraNode, up);


    }

    @Override
    public void changeSwitchStatus(String eui, String node, int up) {
        if (up < 10) {
            controllerService.updateOnline(eui, node,null, up);
            DevDevice deviceConcentrator = deviceService.getById(eui);

            LogManager.getInstance().executeLog(LogTaskFactory.logOnline(deviceConcentrator, node, System.currentTimeMillis(), up));
            sendUserStatus(deviceConcentrator, node, null, up);
        } else if (up == MqttConstant.NODE_JOIN_CODE) {
            // 只有开关处理

        }
    }

    @Override
    public void changeCollectionStatus(String concentrator, String node, int up) {
        collectionService.updateOnline(concentrator, node,null, up);
        DevDevice deviceConcentrator = deviceService.getById(concentrator);
        LogManager.getInstance().executeLog(LogTaskFactory.logOnline(deviceConcentrator, node, System.currentTimeMillis(), up));
        // 将lorawan节点入网不发送
        if (up != MqttConstant.NODE_JOIN_CODE) {
//            sendUserStatus(deviceConcentrator, node, null, up);
        }

    }

    //todo circuit没有进行处理
    private void sendUserStatus(DevDevice deviceConcentrator, String node, String extraNode, int up) {
        SciDeviceStatus sciDeviceStatus;
        String concentrator = deviceConcentrator.getId();
        StringBuilder message = new StringBuilder("设备");
        message.append(deviceConcentrator.getName());
        if(StringUtils.isNotEmpty(extraNode)){
            if(StringUtils.isNotEmpty(node)){
                message.append("上的lora节点").append(extraNode).append("上的地址").append(node);
            }else {
                message.append("上的lora节点").append(extraNode);
            }
        }else {
            message.append("上的节点").append(node);
        }
        if(up == MqttConstant.NODE_JOIN_CODE){
            message.append("入网");
        }else if(up == MqttConstant.DEVICE_ONLINE_CODE) {
            message.append("上线");
        }else {
            message.append("离线");
        }
        sciDeviceStatus = SciDeviceStatus.builder()
                .eui(concentrator)
                .node(node)
                .up(up)
                .message(message.toString())
                .build();

//        userDataService.sendDeviceStatus(sciDeviceStatus);
    }

    @Override
    public void changeDeviceData(CollectionData deviceData) {
        DevCollection deviceCollection = collectionService.getByArg(
                deviceData.getEui(),
                deviceData.getNode(),
                deviceData.getCircuit());
        if (deviceCollection == null) {
            deviceCollection = createCollection(deviceData);
        }
        if (deviceCollection == null) {
            return;
        }
        Date date = new Date();
        String type = deviceData.getType();
        //对降雨量进行特殊处理
        if (type.equals(CollectionTypeEnum.RAINF.getType())) {
            Long oldDate = deviceCollection.getLastTime();
            float realData = 0;
            if (oldDate != null) {
                if (DateUtils.isSameDay(new Date(oldDate),date)) {
                    realData = deviceCollection.getLastData() + deviceData.getData();
                } else {
                    realData = deviceData.getData();
                }
            } else {
                realData = deviceData.getData();
            }
            deviceCollection.setLastData(realData);
            collectionService.updateData(deviceCollection.getId(), realData, date.getTime());
        }else if(type.equals(CollectionTypeEnum.SDUR.getType())){
            Long oldDate = deviceCollection.getLastTime();
            float realData = 0;
            if (oldDate != null) {
                if (DateUtils.isSameDay(new Date(oldDate),date)) {
                    realData = deviceCollection.getLastData() + deviceData.getData();
                } else {
                    realData = deviceData.getData();
                }
            } else {
                realData = deviceData.getData();
            }
            collectionService.updateData(deviceCollection.getId(), realData, date.getTime());
            deviceCollection.setLastData(realData);

        } else {
            deviceCollection.setLastData(deviceData.getData());
            collectionService.updateData(deviceCollection.getId(), deviceData.getData(), date.getTime());
        }
        deviceCollection.setLastTime(date.getTime());

        DevCollectionHistory history = new DevCollectionHistory();
        history.setCollectionId(deviceCollection.getId());
        history.setLastData(deviceData.getData());
        history.setLastTime(date.getTime());
        history.setTenantId(deviceCollection.getTenantId());
        collectionHistoryService.insert(history);
        alarmService.dispatch(deviceCollection);
    }

    private DevCollection createCollection(CollectionData deviceData) {
        synchronized (this){
            String lock = RedisUtil.getCacheStr(String.format(RedisConstant.CREATE_COLLECTION,
                    deviceData.getEui(),deviceData.getNode(),deviceData.getCircuit()));
            if(lock == null){
                RedisUtil.putCacheStr(String.format(RedisConstant.CREATE_COLLECTION,
                        deviceData.getEui(),deviceData.getNode(),deviceData.getCircuit()),"1",20L);
            }else {
                return null;
            }
        }

        String protocol = deviceData.getProtocol();
        int sequence = 0;
        DevDevice devDevice = deviceService.getById(deviceData.getEui());
        if (devDevice == null) {
            return null;
        }

        DevCollection deviceCollection = new DevCollection();
        if (DeviceConstant.SIMPLE.equals(protocol)) {
            sequence = Integer.parseInt(deviceData.getNode());
            deviceCollection.setType(deviceData.getCircuit());
        }
        deviceCollection.setSequence(sequence);
        deviceCollection.setName(deviceData.getNode() + "#" + deviceData.getName());
        deviceCollection.setEui(deviceData.getEui());
        deviceCollection.setNode(deviceData.getNode());
        deviceCollection.setCircuit(deviceData.getCircuit());
        deviceCollection.setOnline(1);
        deviceCollection.setTenantId(devDevice.getTenantId());
        deviceCollection.setProtocol(deviceData.getProtocol());
        deviceCollection.setType(deviceData.getType());
        collectionService.insert(deviceCollection);
        log.info("插入 {}",deviceCollection);
        return deviceCollection;
    }


    @Override
    public void changeSwitch(ControlData switchStatus) {
        DevController deviceSwitch = controllerService.getByArg(
                switchStatus.getEui(),
                switchStatus.getNode(),
                switchStatus.getCircuit()
        );
        if (deviceSwitch == null) {
            deviceSwitch = createSwitch(switchStatus);
        }
        if (deviceSwitch == null) {
            log.error("自动创建开关设备出错   " + switchStatus);
            return;
        }
        Date date = new Date();
        controllerService.updateStatus(switchStatus);
        deviceSwitch.setStatus(switchStatus.getEn());
        deviceSwitch.setLastTime(date.getTime());
    }

    @Override
    public void changeSystem(DeviceSystemPacket systemPacket) {
        DevDevice oldConcentrator = deviceService.getById(systemPacket.getEui());
        if (oldConcentrator == null) {
            return;
        }
        if (systemPacket.getBaud() != null) {
            oldConcentrator.setBaud(systemPacket.getBaud());
        }
        if (systemPacket.getPeriod() != null) {
            oldConcentrator.setPeriod(systemPacket.getPeriod());
        }
        if(systemPacket.getICCID() != null){
            oldConcentrator.setIccid(systemPacket.getICCID());
        }
        oldConcentrator.setOnline(1);
        deviceService.updateSysById(oldConcentrator);
        super.changeSystem(systemPacket);
    }

    @Override
    public void configureSys(DevDevice devDevice) {
        DevDevice oldConcentrator = deviceService.getById(devDevice.getId());
        if (oldConcentrator == null) {
            return;
        }
        if (devDevice.getBaud() != null) {
            oldConcentrator.setBaud(devDevice.getBaud());
        }
        if (devDevice.getPeriod() != null) {
            oldConcentrator.setPeriod(devDevice.getPeriod());
        }
        if(devDevice.getIccid() != null){
            oldConcentrator.setCardNumber(devDevice.getIccid());
        }
        oldConcentrator.setOnline(1);
        deviceService.updateSysById(oldConcentrator);
    }

    private DevController createSwitch(ControlData switchStatus) {
        synchronized (this){
            String lock = RedisUtil.getCacheStr(String.format(RedisConstant.CREATE_CONTROLLER,
                    switchStatus.getEui(),switchStatus.getNode(),switchStatus.getCircuit()));
            if(lock == null){
                RedisUtil.putCacheStr(String.format(RedisConstant.CREATE_CONTROLLER,
                        switchStatus.getEui(),switchStatus.getNode(),switchStatus.getCircuit()),"1",20L);
            }else {
                log.info("没有获取到锁 {}",switchStatus);
                return null;
            }
        }

        DevDevice deviceConcentrator = deviceService.getById(switchStatus.getEui());
        if (deviceConcentrator == null) {
            return null;
        }

        String name = deviceConcentrator.getName();
        if(StringUtils.isNotEmpty(switchStatus.getNode())){
            name = name+"#"+switchStatus.getNode();
        }
        DevController deviceSwitch = new DevController();
        deviceSwitch.setName(name + "#" + switchStatus.getCircuit());
        deviceSwitch.setEui(switchStatus.getEui());
        deviceSwitch.setNode(switchStatus.getNode());
        deviceSwitch.setCircuit(switchStatus.getCircuit());
        deviceSwitch.setOnline(1);
        deviceSwitch.setWaterFeedback(switchStatus.getWaterFeedback());
        deviceSwitch.setType(switchStatus.getDeviceType());
        deviceSwitch.setProtocol(switchStatus.getType());
        deviceSwitch.setTenantId(deviceConcentrator.getTenantId());
        deviceSwitch.setCreateTime(System.currentTimeMillis());
        deviceSwitch.setUpdateTime(System.currentTimeMillis());
        controllerService.insert(deviceSwitch);
        return deviceSwitch;
    }

    @Override
    public void handleHeart(DeviceSystemPacket systemPacket) {
        if(StringUtils.isEmpty(systemPacket.getEui())|| systemPacket.getUpSerial() == null){
            return;
        }
        DeviceHeart deviceHeart = new DeviceHeart();
        deviceHeart.setUpSerial(systemPacket.getUpSerial());
        String topic = String.format(MqttConstant.SCI_GW_CONFIG_TOPIC, systemPacket.getEui());
        String payload = JSON.toJSONString(deviceHeart);
        mqttSendService.send(new MqttContent(topic,payload));

    }
}
